﻿//////////////////////////////////////////////////////////////////////////////
//
// Copyright © 1998-2024 Glodon Company Limited.
//
// Licensed under the MIT License
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the “Software”),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
//////////////////////////////////////////////////////////////////////////////
#include "RevitElementBehaviors.h"
#include "RevitElement.h"
#include "IGenericElement.h"
#include "IElementModelShape.h"
#include "IGraphicsElementShape.h"
#include "DbObjectUtils.h"
#include "IElementStatus.h"
#include "EnableCompileWarning_The_LAST_IncludeInCpp.h"

using namespace gcmp;

DBOBJECT_DATA_DEFINE(RevitElementTransformationComponent)
{
    m_pOwnerElement = nullptr;
}

RevitElement *RevitElementTransformationComponent::GetRevitElementFw()
{
    IElement *pElement = GetOwnerElement();
    if (!pElement)
    {
        return nullptr;
    }
    IGenericElement *pGenericElement = quick_cast<IGenericElement>(pElement);
    if (!pGenericElement)
    {
        return nullptr;
    }
    RevitElement *pRevitElement = quick_cast<RevitElement>(pGenericElement->GetExternalObject());
    return pRevitElement;
}

const RevitElement *RevitElementTransformationComponent::GetRevitElement() const
{
    const IElement *pElement = GetOwnerElement();
    if (!pElement)
    {
        return nullptr;
    }
    const IGenericElement *pGenericElement = quick_cast<IGenericElement>(pElement);
    if (!pGenericElement)
    {
        return nullptr;
    }
    const RevitElement *pAnimInstance = quick_cast<RevitElement>(pGenericElement->GetExternalObject());
    return pAnimInstance;
}

bool RevitElementTransformationComponent::Translate(const IElementMoveContext& moveContext)
{
    Matrix4d matrix;
    matrix.MakeTranslate(moveContext.GetMoveVector());
    return Transform(matrix);
}

bool RevitElementTransformationComponent::Rotate(const Vector3d& origin, const Vector3d& axis, double angle)
{
    Matrix4d matrix;
    matrix.MakeRotate(origin, axis, angle);
    return Transform(matrix);
}

bool RevitElementTransformationComponent::Scale(const Vector3d& basePt, float scaleFactor)
{
    gcmp::Matrix4d scaleMat = Matrix4d::CreateIdentityMatrix4d();
    scaleMat.MakeScale(basePt, scaleFactor);
    return Transform(scaleMat);
}

bool RevitElementTransformationComponent::Transform(const Matrix4d& matrix)
{
    RevitElement *pRevitElement = GetRevitElementFw();
    if (!pRevitElement)
    {
        return false;
    }
    IElement* pOwnedElement = pRevitElement->GetOwnerElement();
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pOwnedElement, L"pOwnedElement为空。",L"GDMPLab",L"2024-03-30");
    IElementModelShape* pShape = pOwnedElement->GetElementModelShape();
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pShape, L"pShape为空。",L"GDMPLab",L"2024-03-30");
    const IGraphicsElementShape * pGRep = pShape->GetGraphicsElementShape();
    if (pGRep)
    {
        // todo: GRep目前只能整体设置，不能原地修改，因此这里只能用Clone；若后续GRep能原地修改了，这里将一并改掉，以提升效率
        OwnerPtr<IGraphicsElementShape> opGRep = TransferOwnershipCast<IGraphicsElementShape>(pGRep->Clone());
        opGRep->Transform(matrix);
        pShape->SetGraphicsElementShape(TransferOwnership(opGRep));
    }

    return true;
}

bool RevitElementTransformationComponent::CanBeMoved(std::wstring* explanation) const
{
    if (GetOwnerElement() == nullptr)
        return true;

    return GetOwnerElement()->GetStatus()->CanBeMoved();
}

bool RevitElementTransformationComponent::CanBeRotated(std::wstring* explanation) const
{
    return true;
}

bool RevitElementTransformationComponent::CanBeScaled(std::wstring* explanation) const
{
    return true;
}
